﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using RoadSign.entity;
using System.Text.RegularExpressions;
using System.IO.Ports;

namespace RoadSign
{
    public partial class Form1 : Form
    {
        public static int INIT = 0;//初始（不能画）
        public static int PAINT = 1;//画图
        public static int FILL = 2;//填充
        public static int MOVE = 3;//移动
        public static int SEND = 4;//发送数据

        Point startPoint; //移动的起始点

        GraphicList graphicList;    //全部图形

        public int status = INIT;//标志状态
        bool isPressed = false;//标志是否处于按下鼠标的状态

        Graphics g;
        private Color newColor = Color.Black;//填充颜色

        public static double realInterval = 1;//实际的喷头喷两点之间的距离(cm)
        private double roadWidth;//设置的道路宽度(cm)

        private List<Point> previewPoints = new List<Point>();//要发送的点（预览用）

        private int interval = 0;//间隔（每几个像素发送一个点）

        private int sendIndex = 0;  //记录发送到第几步(sendIndex != 0 -> 发送过程中)
        private bool sendFlag = false;
        private List<int> dataToSend;//要发送的数据

        public Form1()
        {
            InitializeComponent();

            //创建图形库文件夹
            if (!Directory.Exists("图形库/"))
            {
                Directory.CreateDirectory("图形库");
            }

            this.StartPosition = FormStartPosition.CenterScreen;//窗口居中

            g = panel1.CreateGraphics();//创建一个GDI+对象

            graphicList = new GraphicList(panel1, g);

            this.init();//刷新缩略图区

            //panel上的鼠标滚轮
            panel1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);

            toolStripProgressBar1.Visible = false;//设置发送进度条为不可见

            //panel1.BackgroundImage = Image.FromFile("公路.jpg");//背景图
        }

        //按钮按下的时候进入画线状态，再按一次首尾相连（闭合多边形）
        private void btn_paint_Click(object sender, EventArgs e)
        {
            if (PAINT == status)//闭合
            {
                if (graphicList.items.Count > 0)
                {
                    graphicList.getLast().close();
                    graphicList.paint();
                }
            }

            if (graphicList.items.Count == 0 || graphicList.getLast().points.Count != 0)
            {
                graphicList.items.Add(new GraphicItem(newColor));
                //graphicList.getLast().color = newColor;//改变画图颜色
            }
            status = PAINT;
        }

        //在画板上按下鼠标
        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if (PAINT == status)
            {
                isPressed = true;

                if (graphicList.getLast().points.Count == 0)//表示第一次按下鼠标
                {
                    graphicList.getLast().points.Add(e.Location);
                }
                else
                {
                    graphicList.paint();
                    Pen p = new Pen(graphicList.getLast().color);
                    g.DrawLine(p, graphicList.getLast().getLast(), e.Location);   //绘制最后一条未确定的线条
                }
            }
            else if (FILL == status)
            {
                graphicList.fill(newColor);
                graphicList.paint();
            }
            else if (MOVE == status)
            {
                startPoint = e.Location;
            }
        }

        //在画板上移动鼠标
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (PAINT == status && isPressed)
            {
                graphicList.paint();
                Pen p = new Pen(graphicList.getLast().color);
                g.DrawLine(p, graphicList.getLast().getLast(), e.Location);   //绘制最后一条未确定的线条
            }
        }

        //在画板上松开鼠标
        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (PAINT == status)
            {
                isPressed = false;
                if (graphicList.getLast().getLast() != e.Location)
                {
                    graphicList.getLast().points.Add(e.Location);
                }
                if (graphicList.getLast().points.Count > 1)
                {
                    //显示最后一条直线的长度和角度
                    double[] result = graphicList.getLast().showLine();
                    textBox1.Text = result[0] + "";
                    textBox2.Text = result[1] + "";
                }
            }
            else if (MOVE == status)
            {
                graphicList.move(startPoint, e.Location);
            }
        }

        //填充
        private void btn_fill_Click(object sender, EventArgs e)
        {
            status = FILL;
        }

        //移动
        private void btn_move_Click(object sender, EventArgs e)
        {
            status = MOVE;
        }

        //回退（填充后无法回退）
        private void btn_back_Click(object sender, EventArgs e)
        {
            if (true == graphicList.removeLast())
            {
                graphicList.paint();
            }
            else
            {
                MessageBox.Show("已经填充无法回退");
            }
        }

        //清除绘图
        private void btn_clear_Click(object sender, EventArgs e)
        {
            graphicList.clear();
            graphicList.paint();
            graphicList.items.Add(new GraphicItem(newColor));
            //graphicList.getLast().color = newColor;//改变画图颜色
            textBox1.Clear();
            textBox2.Clear();
        }

        //panel上的鼠标滚轮(缩放)
        private void panel1_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            graphicList.changeSize(e.Delta);
        }

        //发送点预览
        private void btn_prePoints_Click(object sender, EventArgs e)
        {
            if (status != SEND)
            {
                MessageBox.Show("请先发送数据！");
                return;
            }
            foreach (Point p in previewPoints)
            {
                g.FillEllipse(Brushes.Black, p.X - 1, p.Y - 1, 2, 2);
            }
        }

        //背景图
        private void btn_image_Click(object sender, EventArgs e)
        {
            if (panel1.BackgroundImage != null)
                panel1.BackgroundImage = null;
            else
                panel1.BackgroundImage = Image.FromFile("公路.jpg");//背景图
            graphicList.paint();
        }

        //调整直线长度和角度
        private void btn_adjustLine_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Length == 0 || textBox2.Text.Length == 0)
            {
                MessageBox.Show("输入不能为空！");
                return;
            }
            if (!IsNumeric(textBox1.Text) || !IsNumeric(textBox2.Text))
            {
                MessageBox.Show("请输入数字！");
                return;
            }
            int length = (int)Convert.ToDouble(textBox1.Text);
            int agl = (int)Convert.ToDouble(textBox2.Text);
            this.graphicList.getLast().changeLine(length, agl);
            this.graphicList.paint();
        }

        //判断是不是数字
        public static bool IsNumeric(string value)
        {
            return Regex.IsMatch(value, @"^[+-]?\d*[.]?\d*$");
        }

        #region 颜色
        /// <summary>
        /// 颜色。
        /// </summary>		
        private void Black_Click(object sender, System.EventArgs e)
        {
            this.btnColor.BackColor = this.Black.BackColor;
            newColor = this.Black.BackColor;//改变填充颜色
            graphicList.getLast().color = newColor;//改变画图颜色
        }

        private void White_Click(object sender, System.EventArgs e)
        {
            this.btnColor.BackColor = this.White.BackColor;
            newColor = this.White.BackColor;
            graphicList.getLast().color = newColor;
        }

        private void Red_Click(object sender, System.EventArgs e)
        {
            this.btnColor.BackColor = this.Red.BackColor;
            newColor = this.Red.BackColor;
            graphicList.getLast().color = newColor;
        }

        private void blue_Click(object sender, System.EventArgs e)
        {
            this.btnColor.BackColor = this.blue.BackColor;
            newColor = this.blue.BackColor;
            graphicList.getLast().color = newColor;
        }

        private void Yellow_Click(object sender, System.EventArgs e)
        {
            this.btnColor.BackColor = this.Yellow.BackColor;
            newColor = this.Yellow.BackColor;
            graphicList.getLast().color = newColor;
        }

        //private void LawnGreen_Click(object sender, System.EventArgs e)
        //{
        //    this.btnColor.BackColor = this.LawnGreen.BackColor;
        //    newColor = this.LawnGreen.BackColor;
        //    graphicList.getLast().color = newColor;
        //}

        //private void Cyan_Click(object sender, System.EventArgs e)
        //{
        //    this.btnColor.BackColor = this.Cyan.BackColor;
        //    newColor = this.Cyan.BackColor;
        //    graphicList.getLast().color = newColor;
        //}

        //private void Magenta_Click(object sender, System.EventArgs e)
        //{
        //    this.btnColor.BackColor = this.Magenta.BackColor;
        //    newColor = this.Magenta.BackColor;
        //    graphicList.getLast().color = newColor;
        //}

        //private void MoreColor_Click(object sender, System.EventArgs e)
        //{
        //    if (colorDialog.ShowDialog() == DialogResult.OK)
        //    {
        //        this.btnColor.BackColor = colorDialog.Color;
        //        newColor = colorDialog.Color;
        //        graphicList.getLast().color = newColor;
        //    }
        //}
        #endregion

        //扫描串口
        public void scanPort()
        {
            string[] portlist = SerialPort.GetPortNames();
            comboBox1.Items.Clear();
            for (int i = 0; i < portlist.Length; i++)
            {
                this.comboBox1.Items.Add(portlist[i]);
                if (i == 0)
                {
                    this.comboBox1.SelectedIndex = 0;//默认选择第一项
                }
            }
        }

        //重新扫描串口
        private void comboBox1_Click(object sender, EventArgs e)
        {
            scanPort();
        }

        //建立串口连接
        private void btn_open_Click(object sender, EventArgs e)
        {
            try
            {
                if (!serialPort1.IsOpen)
                {
                    if (comboBox1.Text.Length == 0)
                    {
                        MessageBox.Show("没有扫描到串口");
                        return;
                    }

                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.Open();
                    toolStripStatusLabel1.Text = " 已连接 ";
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
        }

        //关闭串口连接
        private void btn_close_Click(object sender, EventArgs e)
        {
            //重置发送进度
            sendIndex = 0;
            toolStripProgressBar1.Value = 0;
            toolStripProgressBar1.Visible = false;

            serialPort1.Close();
            toolStripStatusLabel1.Text = " 未连接 ";
        }

        //得到绘图面板上某座标的颜色
        private Color getColorByPos(Point pos)
        {
            IntPtr intptr = g.GetHdc();
            int color = GraphicList.GetPixel(intptr, pos.X, pos.Y);
            Color color2 = Color.FromArgb(color);
            g.Dispose();
            g = panel1.CreateGraphics();//恢复g
            return color2;
        }

        //得到要发送的数据
        private List<int> getDataToSend()
        {
            List<int> sendData = new List<int>();
            Dictionary<string, int> border = graphicList.getBorder();
            int width = (border["right"] - border["left"]) / interval + 1;
            int height = (border["bottom"] - border["top"]) / interval + 1;

            sendData.Add(width);
            sendData.Add(height);

            bool flag = true;
            for (int i = 0; i < height; i++)
            {
                if (flag)//左到右
                {
                    for (int j = 0; j < width; j++)
                    {
                        Point pos = new Point();
                        pos.X = border["left"] + j * interval;
                        pos.Y = border["bottom"] - i * interval;
                        Color color = this.getColorByPos(pos);
                        previewPoints.Add(pos);
                        int data;
                        if (color == Color.FromArgb(0, 0, 255, 255))//黄色
                        {
                            data = 1;
                        }
                        else if (color == Color.FromArgb(0, 255, 0, 0))//蓝色(红色?)
                        {
                            data = 3;
                        }
                        else if (color == Color.FromArgb(0, 0, 0, 255))//红色(蓝色?)
                        {
                            data = 2;
                        }
                        else//白色或其他
                        {
                            data = 0;
                        }
                        sendData.Add(data);
                    }
                }
                else
                {
                    for (int j = width - 1; j >= 0; j--)
                    {
                        Point pos = new Point();
                        pos.X = border["left"] + j * interval;
                        pos.Y = border["bottom"] - i * interval;
                        Color color = this.getColorByPos(pos);
                        previewPoints.Add(pos);
                        int data;
                        if (color == Color.FromArgb(0, 0, 255, 255))//黄色
                        {
                            data = 1;
                        }
                        else if (color == Color.FromArgb(0, 255, 0, 0))//蓝色(红色?)
                        {
                            data = 3;
                        }
                        else if (color == Color.FromArgb(0, 0, 0, 255))//红色(蓝色?)
                        {
                            data = 2;
                        }
                        else//白色或其他
                        {
                            data = 0;
                        }
                        sendData.Add(data);
                    }

                }
                flag = !flag;
            }
            return sendData;
        }

        //首次点击发送数据（serialPort1的发送端口名称：COM1，用虚拟串口vspd和一个串口助手结合可模拟发送和接收）
        private void btn_send_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                MessageBox.Show("请先建立连接！");
                return;
            }

            if (interval == 0)
            {
                MessageBox.Show("请先设置参数！");
                return;
            }

            //有图像并且为第一次才发送
            if (graphicList.items.Count != 0 && graphicList.items[0].points.Count > 1 && sendIndex == 0)
            {
                status = SEND;
                dataToSend = getDataToSend();//得到发送数据

                //初始化发送进度条
                toolStripProgressBar1.Maximum = dataToSend.Count;
                toolStripProgressBar1.Step = 1;
                toolStripProgressBar1.Visible = true;

                sendData();
            }
        }

        //发送数据
        private void sendData()
        {
            if (sendIndex == 0 && sendFlag == false)
            {
                serialPort1.Write("GO.");
                toolStripProgressBar1.PerformStep();
                sendFlag = true;
            }
            else if (sendIndex == 0 && sendFlag == true)
            {
                serialPort1.Write("L" + dataToSend[sendIndex++] + ".");
                toolStripProgressBar1.PerformStep();
                sendFlag = false;
            }
            else if (sendIndex == 1)
            {
                serialPort1.Write("W" + dataToSend[sendIndex++] + ".");
                toolStripProgressBar1.PerformStep();
            }
            else
            {
                serialPort1.Write(dataToSend[sendIndex++] + ".");
                toolStripProgressBar1.PerformStep();
            }
        }

        //声明一个委托类型，该委托类型无输入参数和输出参数
        public delegate void ProcessDelegate();

        //接收到数据的时候(线程调用主线程中的控件)
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //实例化一个委托变量，使用匿名方法构造
            ProcessDelegate showProcess = delegate()
            {
                string feedback = serialPort1.ReadExisting();
                if (feedback == "get" || feedback == "get wid" || feedback == "get len")
                {
                    sendData();
                }
                else if (feedback == "finish")
                {
                    DialogResult dr = MessageBox.Show("完成");
                    if (dr == DialogResult.OK)
                    {
                        //重置发送进度
                        sendIndex = 0;
                        toolStripProgressBar1.Value = 0;
                        toolStripProgressBar1.Visible = false;
                    }
                }
            };
            this.Invoke(showProcess);
        }

        //点击保存图片和列表
        private void btn_save_Click(object sender, EventArgs e)
        {
            save();
        }

        //生成图片
        private Bitmap getCorrectBitMap()
        {
            //得到图形的边界
            Dictionary<string, int> border = graphicList.getBorder();

            //分别计算出生成的缩略图距离左上角的偏差
            int marginLeft = border["left"];
            int marginTop = border["top"];
            if (marginLeft > 10)
                marginLeft -= 10;
            else
                marginLeft = 0;
            if (marginTop > 10)
                marginTop -= 10;
            else
                marginTop = 0;

            int imageWidth = (border["right"] - border["left"]) + (border["left"] - marginLeft) + 10;
            int imageHeight = (border["bottom"] - border["top"]) + (border["top"] - marginTop) + 10;
            Bitmap myBitmap = new Bitmap(imageWidth, imageHeight);

            Graphics g = Graphics.FromImage(myBitmap);

            //panel左上角相对于屏幕的位置
            Point panelLocation = panel1.PointToScreen(new Point(0, 0));
            //屏幕截图
            g.CopyFromScreen(panelLocation.X + marginLeft, panelLocation.Y + marginTop, 0, 0, new Size(imageWidth, imageHeight));

            g.Dispose();

            return myBitmap;
        }

        //根据点列表生成图片并保存
        private void save()
        {
            if (graphicList.items.Count == 0 || this.graphicList.items[0].points.Count < 2)
            {
                return;
            }
            Bitmap bitmap = this.getCorrectBitMap();

            if (bitmap != null)
            {
                save(bitmap);
                this.flowLayoutPanel1.Controls.Clear();
                this.init();
            }
            else
                MessageBox.Show("图片生成出错!");

        }

        //这里写弹出对话框并保存列表和图片的代码
        private void save(Bitmap bitmap)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            String name= Convert.ToInt64(ts.TotalSeconds).ToString();  
            String filename ="图形库/"+ name+".dat";
            Stream stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
            BinaryFormatter bf = new BinaryFormatter();
            try
            {
                bf.Serialize(stream, graphicList.items);
                bf.Serialize(stream, graphicList.fillPoints);
                bf.Serialize(stream, bitmap);
                stream.Flush();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                stream.Close();
            }
        }

        //初始化flowLayoutPanel,添加自定义控件
        private void init()
        {
            DirectoryInfo folder = new DirectoryInfo("图形库/");
            FileInfo[] files = folder.GetFiles();
            foreach (FileInfo fileInfo in files)
            {
                Bitmap bitmap = this.loadImageFromFile(fileInfo.FullName);
                MyPictureBox pictureBox = new MyPictureBox(this, bitmap, fileInfo.FullName);
                this.flowLayoutPanel1.Controls.Add(pictureBox);
            }
        }

        private Bitmap loadImageFromFile(string filename)
        {
            Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            Bitmap bitmap = null;
            BinaryFormatter bf = new BinaryFormatter();
            try
            {
                status = INIT;//打开绘图后锁定不能画线，否则可能会出现一些bug

                bf.Deserialize(stream);
                bf.Deserialize(stream);
                bitmap = (Bitmap)bf.Deserialize(stream);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                stream.Close();
            }
            return bitmap;
        }

        //显示缩略图
        public void show(string filename)
        {
            if (SEND == status)
                return;

            Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            BinaryFormatter bf = new BinaryFormatter();
            try
            {
                status = INIT;//打开绘图后锁定不能画线，否则可能会出现一些bug

                List<GraphicItem> items = (List<GraphicItem>)bf.Deserialize(stream);
                List<ColorPoint> colors = (List<ColorPoint>)bf.Deserialize(stream);
                graphicList.items = items;
                graphicList.fillPoints = colors;
                graphicList.paint();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                stream.Close();
            }
        }

        //菜单栏保存绘图
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            save();
        }

        //退出程序
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            Application.Exit();
        }

        //使用提示
        private void hintToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("使用提示：\n鼠标滚轮：缩放\n形状上右键：删除\n");
        }

        //关于
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("RoadSign");
        }

        //解决最小化恢复后图像消失的问题
        protected override void OnResize(EventArgs e)
        {
            if (WindowState == FormWindowState.Normal)
            {
                if (graphicList != null)
                    graphicList.paint();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            scanPort();//扫描串口

            this.Visible = false;
            StartForm start = new StartForm(this);
            start.ShowDialog();
        }

        public FlowLayoutPanel getPanel()
        {
            return this.flowLayoutPanel1;
        }

        //设置参数
        private void btn_setParameter_Click(object sender, EventArgs e)
        {
            if (status == SEND)
            {
                MessageBox.Show("发送过程中不能设置参数！");
                return;
            }

            string input_roadWidth = textBox_roadWidth.Text.Trim();
            if (input_roadWidth.Length == 0)
            {
                MessageBox.Show("输入不能为空！");
            }
            else
            {
                if (IsNumeric(input_roadWidth))
                {
                    this.roadWidth = Convert.ToDouble(input_roadWidth);
                }
                else
                {
                    MessageBox.Show("请输入数字！");
                    textBox_roadWidth.Clear();
                }
            }

            interval = (int)(panel1.Width * realInterval * 1.0 / roadWidth);

            double graphicWidth = trackBar1.Value;
            double oldGraphicWidthPixel = graphicList.getBorder()["right"] - graphicList.getBorder()["left"];
            double newGraphicWidthPixel = panel1.Width * graphicWidth * 1.0 / roadWidth;
            graphicList.changeSize(newGraphicWidthPixel / oldGraphicWidthPixel);
            graphicList.paint();
        }

        //显示trackBar（滑动条）的数值
        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            lbl_trackBar.Text = trackBar1.Value + "";
        }

    }
}
